#include "SQLOrderBy.h"

#include "../visitor/SQLASTVisitor.h"
#include "../../utils/ifeq.h"
#include "../../utils/listTran.h"
#include "../../utils/log.h"

SQLOrderBy::SQLOrderBy()
    : buf(make_string_ptr(" ")), parent(NULL)
{
  attributes = std::make_shared<std::map<std::string, Object_ptr>>();
  items = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();
}
SQLOrderBy::~SQLOrderBy()
{

  // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLOrderBy::~SQLOrderBy, step 1 " << std::endl;
  // for (std::list<SQLSelectOrderByItem_ptr>::iterator it = items->begin(); it != items->end(); ++it)
  // {
  //   // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLOrderBy::~SQLOrderBy, step 1.1 " << std::endl;
  //   delete *it;
  // }
  // items->clear();

  // for (auto it = attributes->begin(); it != attributes->end(); ++it)
  // {
  //   // std::cout <<  "++++\t" << __FILE__ << ": " << __LINE__ << ", in SQLOrderBy::~SQLOrderBy, step 1.2 " << std::endl;
  //   // Object_ptr Ptr = Object_ptr(it->second);
  //   // delete Ptr;
  // }

  // if (parent != NULL)
  // {
  //   // delete parent;
  //   parent = NULL;
  // }
}
SQLOrderBy::SQLOrderBy(SQLExpr_ptr theExpr)
    : buf(make_string_ptr(" ")), parent(NULL)
{
  attributes = std::make_shared<std::map<std::string, Object_ptr>>();
  items = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();

  SQLSelectOrderByItem_ptr item = SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(theExpr));
  item->setParent(SharedObject(SQLOrderBy));
  items->push_back(item);
}

SQLOrderBy::SQLOrderBy(SQLExpr_ptr expr, SQLOrderingSpecification_ptr type)
{
  attributes = std::make_shared<std::map<std::string, Object_ptr>>();
  items = std::make_shared<std::list<SQLSelectOrderByItem_ptr>>();

  SQLSelectOrderByItem_ptr item = SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(expr, type));
  addItem(item);
}

void SQLOrderBy::addItem(SQLSelectOrderByItem_ptr item)
{
  if (item != NULL)
  {
    item->setParent(SharedObject(SQLOrderBy));
  }
  items->push_back(item);
}

void SQLOrderBy::addItem(SQLExpr_ptr item)
{
  addItem(SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem(item)));
}

void SQLOrderBy::addItem(SQLExpr_ptr expr, SQLOrderingSpecification_ptr type)
{
  SQLSelectOrderByItem_ptr item = createItem();
  item->setExpr(expr);
  item->setType(type);
  addItem(item);
}

SQLSelectOrderByItem_list_ptr SQLOrderBy::getItems()
{
  return items;
}

void SQLOrderBy::accept0(SQLASTVisitor_ptr v)
{
  if (v->visit(SharedObject(SQLOrderBy)))
  {
    auto it_items = this->items->begin();
    for (int i = 0; i < this->items->size(); i++)
    {
      std::advance(it_items, i);
      SQLSelectOrderByItem_ptr item = *it_items;
      item->accept(v);
    }
  }

  v->endVisit(SharedObject(SQLOrderBy));
}

// int SQLOrderBy::hashCode() {
// int prime = 31;
// int result = 1;
// result = prime * result + ((items == NULL) ? 0 : items.hashCode());
// return result;
//}

bool SQLOrderBy::equals(Object_ptr obj)
{
  if (this == obj.get())
    return true;
  if (obj == NULL)
    return false;
  if (getClass() != obj->getClass())
    return false;
  SQLOrderBy_ptr other = std::dynamic_pointer_cast<SQLOrderBy>(obj);
  if (items->empty())
  {
    if (!other->items->empty())
      return false;
  }
  else if (!(items == other->items))
    return false;
  return true;
}

SQLObject_ptr SQLOrderBy::getParent()
{
  return parent;
}

void SQLOrderBy::setParent(SQLObject_ptr theParent)
{
  parent = theParent;
}

std::shared_ptr<std::map<std::string, Object_ptr>> SQLOrderBy::getAttributes()
{
  // if (attributes.empty()) {
  // attributes = new Hashstd::map<string_ptr , Object>(1);
  //}
  if (attributes == nullptr)
  {
    LOG_INFO << "attributes == nullptr";
    attributes = std::make_shared<std::map<std::string, Object_ptr>>();
  }
  LOG_INFO << "attributes.use_count:" << attributes.use_count();
  return attributes;
}

// Object_ptr SQLOrderBy::getAttribute(string_ptr name)
// {
//   // if (attributes == NULL) {
//   // return NULL;
//   //}

//   // test is empty is unneccessary??
//   // map<string_ptr ,Object &>::const_iterator it = attributes.find(name);
//   // if (it != attributes.end())
//   //{
//   // return attributes.find(name)->second;
//   //}

//   return attributes->find(name)->second;
// }

// void SQLOrderBy::putAttribute(string_ptr name, Object_ptr value)
// {
//   // if (attributes == NULL) {
//   // attributes = new Hashstd::map<string_ptr , Object>(1);
//   //}

//   attributes->insert(std::make_pair(name, value));
//   // attributes.put(name, value);
// }

std::shared_ptr<std::map<std::string, Object_ptr>> SQLOrderBy::getAttributesDirect()
{
  return attributes;
}

void SQLOrderBy::output(std::stringstream * theBuf)
{
  // buf.append(super::toString());
  // buf.push_back(super::toString());
  // std::cout << super::toString() << std::endl;
  (*theBuf) << super::toString()->c_str();
}

// string_ptr SQLOrderBy::toString() {
// output(buf);
// return buf;
//}

SQLSelectOrderByItem_ptr SQLOrderBy::createItem()
{
  return SQLSelectOrderByItem_ptr(new SQLSelectOrderByItem());
}

// SQLOrderBy *SQLOrderBy::clone()
SQLObject_ptr SQLOrderBy::clone()
{
  SQLObject_ptr clone_tmp = SQLOrderBy_ptr(new SQLOrderBy());
  SQLOrderBy_ptr clone_res = std::dynamic_pointer_cast<SQLOrderBy>(clone_tmp);

  //   return clone_res;

  // SQLOrderBy *x = new SQLOrderBy();

  for (SQLSelectOrderByItem_ptr item : *items)
  {
    SQLSelectOrderByItem_ptr item1 = (std::dynamic_pointer_cast<SQLSelectOrderByItem>(item->clone()));
    item1->setParent(clone_res);
    clone_res->items->push_back(item1);
  }

  // x->siblings = siblings;

  return clone_res;
}